﻿//
//  Copyright (c) 2009 Liang Quan Qing.
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//  1. Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in the
//     documentation and/or other materials provided with the distribution.
//
//  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
//  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
//  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
//  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
//  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
//  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
//  SUCH DAMAGE.
//

#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "fastconv.h"

static void ShowHelp(void);
static int TestStyle0(int argc, char** argv);
static int TestStyle1(int argc, char** argv);   // sbcs
static int TestStyle2(int argc, char** argv);   // cp932
static int TestStyle3(int argc, char** argv);   // dbcs
static int TestStyle200(int argc, char** argv);   // ansi to unicode map
static int GetInfo(int argc, char** argv);

static int usedef;
static unsigned char defchar[16];
static WChar_t defwchar;
FILE * fpIn, *fpOut;

int main(int argc, char** argv)
{
    int style;
    if ( argc == 1 )
        ShowHelp();
    style = atoi(argv[1]);
    if ( style == 0 )
        TestStyle0(argc, argv);
    else if ( style == 1 )
        TestStyle1(argc, argv);         // sbcs
    else if ( style == 2 )
        TestStyle2(argc, argv);         // cp932
    else if ( style == 3 )
        TestStyle3(argc, argv);         // dbcs
    else if ( style == 200 )
        TestStyle200(argc, argv);       // build MapTable
    return 0;
}

static void ShowHelp(void)
{
    printf("testfcnv  style  action  charset  boUseDefault  defchar  defwchar  infile  outfile\n");
    exit(0);
}

static int GetInfo(int argc, char** argv)
{
    usedef = atoi(argv[4]);
    memset(defchar, 0, 16);
    strncpy(defchar, argv[5], 8);
    defwchar = argv[6][0];
    fpIn = fopen(argv[7], "rb");
    if ( fpIn == NULL )
    {
        printf("cannot open file : %s\n", argv[7]);
        exit(1);
    }
    fpOut = fopen(argv[8], "wb");
}

static int TestStyle0(int argc, char** argv)
{
    unsigned char* pSrcBuf, *pDstBuf;
    unsigned flen;
    fcnv_t cv;

    GetInfo(argc,argv);
    flen = filelength(_fileno(fpIn));
    pSrcBuf = (unsigned char*)malloc(flen+16);
    memset(pSrcBuf, 0, flen+16);
    pDstBuf = (unsigned char*)malloc(4*flen+64);
    memset(pDstBuf, 0, 4*flen+64);
    //---
    fread(pSrcBuf, 1, flen, fpIn);
    printf("Charset = %s\n", argv[3]);
    fcnv_Init(argv[3], &cv);
    fcnv_Setup(&cv, usedef, defchar, defwchar);
    printf("Use default char: %d\n", usedef);
    printf("default char: %s\n", defchar);
    printf("default wchar: 0x%04x\n", defwchar);
    //---
    if ( !stricmp(argv[2], "t16") )
    {
        fcnv_ToUTF16(&cv, pSrcBuf, flen, (WChar_t*)pDstBuf, (4*flen)/2);
        fwrite(pDstBuf, 1, cv.outCount * 2, fpOut);
    }
    else if ( !stricmp(argv[2], "f16") )
    {
        fcnv_FromUTF16(&cv, (WChar_t*)pSrcBuf, flen/2, pDstBuf, 4*flen);
        fwrite(pDstBuf, 1, cv.outCount, fpOut);
    }
    else if ( !stricmp(argv[2], "t8") )
    {
        fcnv_ToUTF8(&cv, pSrcBuf, flen, pDstBuf, 4*flen);
        fwrite(pDstBuf, 1, cv.outCount*1, fpOut);
    }
    else if ( !stricmp(argv[2], "f8") )
    {
        fcnv_FromUTF8(&cv, pSrcBuf, flen, pDstBuf, 4*flen);
        fwrite(pDstBuf, 1, cv.outCount, fpOut);
    }
    else if ( !stricmp(argv[2], "t32") )
    {
        fcnv_ToUTF32(&cv, pSrcBuf, flen, pDstBuf, (4*flen)/4);
        fwrite(pDstBuf, 1, cv.outCount*4, fpOut);
    }
    else if ( !stricmp(argv[2], "f32") )
    {
        fcnv_FromUTF32(&cv, pSrcBuf, (flen)/4, pDstBuf, 4*flen);
        fwrite(pDstBuf, 1, cv.outCount, fpOut);
    }


    printf("\n");
    printf("In    : %d\n",cv.inCount);
    printf("Out   : %d\n",cv.outCount);
    printf("Error : %d\n",cv.error);
    //---
    free(pSrcBuf);
    free(pDstBuf);
    fclose(fpIn);
    fclose(fpOut);
}

struct testtype_1{
    unsigned char enable;
    unsigned int  unicode;
};

struct testtype_2{
    unsigned char enable;
    unsigned int  a_code;
};

static int TestStyle1(int argc, char** argv)    // sbcs
{
    fcnv_t cv;
    struct testtype_1  testdata[65536];
    unsigned int i, blen, wlen;

    memset(testdata, 0, sizeof(testdata));
    GetInfo(argc,argv);
    //---
    printf("Charset = %s\n", argv[3]);
    fcnv_Init(argv[3], &cv);
    fcnv_Setup(&cv, usedef, defchar, defwchar);
    printf("Use default char: %d\n", usedef);
    printf("default char: %s\n", defchar);
    printf("default wchar: 0x%04x\n", defwchar);
    //---
    for (i = 0; i < 0x100; i++)
    {
        unsigned char bstr[4];
        unsigned short wstr[4];
        if ( i < 0x100 )
        {
            bstr[0] = (unsigned char)i;
            bstr[1] = 0;
            blen = 1;
        }
        else if ( i >= 0x8000 )
        {
            bstr[0] = (unsigned char)((i>>8)&0xff);
            bstr[1] = (unsigned char)(i&0xff);
            bstr[2] = 0;
            blen = 2;
        }
        else
            continue;

        fcnv_ToUTF16(&cv, bstr, blen, wstr, 4);
        printf("code:%04x  In:%d, Out:%d, Error:%d\n",i, cv.inCount, cv.outCount, cv.error);

        if (cv.error == FCNV_OK)
        {
            testdata[i].enable = 1;
            testdata[i].unicode = wstr[0];
        }
    }

    for (i = 0; i < 65536; i++)
    {
        if (testdata[i].enable)
        {
            fprintf(fpOut, "0x%02X\t0x%04X\n", i, testdata[i].unicode);
        }
    }
    //---
    fclose(fpIn);
    fclose(fpOut);
}

static int TestStyle2(int argc, char** argv)    //cp932
{
    fcnv_t cv;
    struct testtype_1  testdata[65536];
    unsigned int i, blen, wlen;

    memset(testdata, 0, sizeof(testdata));
    GetInfo(argc,argv);
    //---
    printf("Charset = %s\n", argv[3]);
    fcnv_Init(argv[3], &cv);
    fcnv_Setup(&cv, usedef, defchar, defwchar);
    printf("Use default char: %d\n", usedef);
    printf("default char: %s\n", defchar);
    printf("default wchar: 0x%04x\n", defwchar);
    //---
    for (i = 0; i < 65536; i++)
    {
        unsigned char bstr[4];
        unsigned short wstr[4];
        if ( i < 0x100 )
        {
            bstr[0] = (unsigned char)i;
            bstr[1] = 0;
            blen = 1;
        }
        else if ( (i >= 0x8000 && i <= 0x9fff)||(i >= 0xE000 && i <= 0xffff) )
        {
            bstr[0] = (unsigned char)((i>>8)&0xff);
            bstr[1] = (unsigned char)(i&0xff);
            bstr[2] = 0;
            blen = 2;
        }
        else
            continue;

        fcnv_ToUTF16(&cv, bstr, blen, wstr, 4);
        printf("code:%04x  In:%d, Out:%d, Error:%d\n",i, cv.inCount, cv.outCount, cv.error);

        if (cv.error == FCNV_OK)
        {
            testdata[i].enable = 1;
            testdata[i].unicode = wstr[0];
        }
    }

    for (i = 0; i < 65536; i++)
    {
        if (testdata[i].enable)
        {
            fprintf(fpOut, "0x%02X\t0x%04X\n", i, testdata[i].unicode);
        }
    }
    //---
    fclose(fpIn);
    fclose(fpOut);
}

static int TestStyle3(int argc, char** argv)    //dbcs
{
    fcnv_t cv;
    struct testtype_1  testdata[65536];
    unsigned int i, blen, wlen;

    memset(testdata, 0, sizeof(testdata));
    GetInfo(argc,argv);
    //---
    printf("Charset = %s\n", argv[3]);
    fcnv_Init(argv[3], &cv);
    fcnv_Setup(&cv, usedef, defchar, defwchar);
    printf("Use default char: %d\n", usedef);
    printf("default char: %s\n", defchar);
    printf("default wchar: 0x%04x\n", defwchar);
    //---
    for (i = 0; i < 65536; i++)
    {
        unsigned char bstr[4];
        unsigned short wstr[4];
        if ( i < 0x100 )
        {
            bstr[0] = (unsigned char)i;
            bstr[1] = 0;
            blen = 1;
            if (fcnv_IsLeadByte(&cv, bstr))
                continue;
        }
        else if ( i >= 0x8000 )
        {
            bstr[0] = (unsigned char)((i>>8)&0xff);
            bstr[1] = (unsigned char)(i&0xff);
            bstr[2] = 0;
            blen = 2;
            if (!fcnv_IsLeadByte(&cv, bstr))
                continue;
        }
        else
            continue;

        fcnv_ToUTF16(&cv, bstr, blen, wstr, 4);
        printf("code:%04x  In:%d, Out:%d, Error:%d\n",i, cv.inCount, cv.outCount, cv.error);

        if (cv.error == FCNV_OK)
        {
            testdata[i].enable = 1;
            testdata[i].unicode = wstr[0];
        }
    }

    for (i = 0; i < 65536; i++)
    {
        if (testdata[i].enable)
        {
            fprintf(fpOut, "0x%02X\t0x%04X\n", i, testdata[i].unicode);
        }
    }
    //---
    fclose(fpIn);
    fclose(fpOut);
}

static int TestStyle200(int argc, char** argv)    // map
{
    fcnv_t cv;
    struct testtype_1  *testdata;
    struct testtype_2  *a_test_data;
    unsigned int i, blen, wlen;

    GetInfo(argc,argv);

    testdata = (struct testtype_1*) malloc(65536*sizeof(struct testtype_1));
    a_test_data = (struct testtype_2*) malloc(65536*sizeof(struct testtype_2));
    memset(testdata, 0, 65536*sizeof(struct testtype_1));
    memset(a_test_data, 0, 65536*sizeof(struct testtype_2));
    //---
    printf("Charset = %s\n", argv[3]);
    fcnv_Init(argv[3], &cv);
    fcnv_Setup(&cv, usedef, defchar, defwchar);
    printf("Use default char: %d\n", usedef);
    printf("default char: %s\n", defchar);
    printf("default wchar: 0x%04x\n", defwchar);
    //---
    for (i = 0; i < 65536; i++)
    {
        unsigned char bstr[4];
        unsigned short wstr[4];
        if ( i < 0x100 )
        {
            bstr[0] = (unsigned char)i;
            bstr[1] = 0;
            blen = 1;
            if (fcnv_IsLeadByte(&cv, bstr))
                continue;
        }
        else if ( i >= 0x8000 )
        {
            bstr[0] = (unsigned char)((i>>8)&0xff);
            bstr[1] = (unsigned char)(i&0xff);
            bstr[2] = 0;
            blen = 2;
            if (!fcnv_IsLeadByte(&cv, bstr))
                continue;
        }
        else
            continue;

        fcnv_ToUTF16(&cv, bstr, blen, wstr, 4);
        printf("code:%04x  In:%d, Out:%d, Error:%d\n",i, cv.inCount, cv.outCount, cv.error);

        if (cv.error == FCNV_OK)
        {
            testdata[i].enable = 1;
            testdata[i].unicode = (unsigned short) wstr[0];

            a_test_data[(unsigned short) wstr[0]].enable = 1;
            a_test_data[(unsigned short) wstr[0]].a_code = (unsigned short) i;
        }
    }

    for (i = 0; i < 65536; i++)
    {
        if (testdata[i].enable)
        {
            fprintf(fpOut, "0x%02X\t0x%04X\n", i, testdata[i].unicode);
        }
    }
    fprintf(fpOut, "\n\n==========================================================================\n\n");
    for (i = 0; i < 65536; i++)
    {
        if (a_test_data[i].enable)
        {
            fprintf(fpOut, "0x%04X\t0x%04X\n", i, a_test_data[i].a_code);
        }
    }

    free(testdata);
    free(a_test_data);
    //---
    fclose(fpIn);
    fclose(fpOut);
}





